#include <cstdlib>
#include <gtest/gtest.h>
#include <dirent.h>
#include <iostream>
#include <fstream>
#include <unordered_set>
#include "log/diagosapi.h"
#include "test_comm.h"

class TestDiagosAPIFixture : public ::testing::Test
{
public:
    void SetUp() override
    {
        ASSERT_FALSE(IsRoot());
        CWD = GetCwd();
        ASSERT_FALSE(CWD.empty());

        FileNamePrefix = __FUNCTION__;
    }

    std::string GetCwd() const
    {
        char pChCwd[1024];
        if (!getcwd(pChCwd, sizeof(pChCwd)))
        {
            return "";
        }
        return std::string(pChCwd);
    }

    bool IsRoot()
    {
        uid_t uid = getuid();
        gid_t gid = getegid();
        return uid == 0 || gid == 0;
    }

    const std::string GetTestFileName(int32_t index) const { return FileNamePrefix + "-" + std::to_string(index); }

    void CreateFile(const std::string& filename) const
    {
        std::fstream fs;
        fs.open(filename, std::ios::out);
        if (!fs)
        {
            FAIL() << "create " << filename << " failed: " << strerror(errno) << "\n";
        }
        else
        {
            fs << filename << "\n";
        }
        fs.close();
    }

    std::string CWD;
    std::string FileNamePrefix;
};

TEST_F(TestDiagosAPIFixture, TestMkdir)
{
    std::string dirpath = CWD + "/" + "test_dir";
    EXPECT_EQ(DiagOSAPI::Mkdir(dirpath), 0);
    EXPECT_TRUE(IsDirExists(dirpath));
    EXPECT_EQ(DiagOSAPI::RemoveF(dirpath), 0);
    EXPECT_FALSE(IsDirExists(dirpath));
}

TEST_F(TestDiagosAPIFixture, TestMkdirException)
{
    std::string dirpath = "/PATH/NOT_EXIST";
    EXPECT_EQ(DiagOSAPI::Mkdir(dirpath), -1);
}

TEST_F(TestDiagosAPIFixture, TestFileOp)
{
    const std::string destDirName = "test_dir";
    const std::string destDirPath = CWD + "/" + destDirName;
    const std::string srcDirPath = CWD;

    EXPECT_EQ(DiagOSAPI::Mkdir(destDirPath), 0);

    for (int i = 0; i < 5; i++)
    {
        std::string srcPath = srcDirPath + "/" + GetTestFileName(i);
        CreateFile(srcPath);
        EXPECT_TRUE(IsFileExists(srcPath));
    }

    for (int32_t i = 0; i < 5; i++)
    {
        std::string srcPath = srcDirPath + "/" + GetTestFileName(i);
        std::string dstPath = destDirPath + "/" + GetTestFileName(i);
        EXPECT_EQ(DiagOSAPI::CopyFile(srcPath, dstPath), 0);
        EXPECT_TRUE(IsFileExists(dstPath));
    }

    {
        std::vector<std::string> fileList;
        std::unordered_set<std::string> fileSet, refFileSet;
        std::string dirPath = CWD + "/" + destDirName;
        EXPECT_EQ(DiagOSAPI::ListFile(dirPath, fileList, false), 0);
        fileSet.insert(fileList.begin(), fileList.end());
        for (int i = 0; i < 5; i++) { refFileSet.insert(dirPath + "/" + GetTestFileName(i)); }
        EXPECT_EQ(fileSet, refFileSet);
    }

    {
        std::string packName = CWD + "/" + destDirName + ".tar.gz";
        EXPECT_EQ(DiagOSAPI::PackTargz(CWD, destDirName, destDirName), 0);
        EXPECT_TRUE(IsFileExists(packName));

        EXPECT_EQ(DiagOSAPI::RemoveF(packName), 0);
        EXPECT_FALSE(IsFileExists(packName));
    }

    {
        std::string filePath = srcDirPath + "/" + GetTestFileName(0);
        uint64_t sz = 0;
        int32_t filesize = DiagOSAPI::FileSize(filePath, sz);

        // 获得文件大小
        std::stringstream res;
        std::string cmd = "stat -c %s " + filePath;
        EXPECT_EQ(DiagOSAPI::Popen(cmd, res), 0);
        EXPECT_EQ(sz, atoi(res.str().c_str()));
    }

    for (int i = 0; i < 5; i++)
    {
        std::string srcPath = srcDirPath + "/" + GetTestFileName(i);
        EXPECT_EQ(DiagOSAPI::RemoveF(srcPath), 0);
        EXPECT_FALSE(IsFileExists(srcPath));

        std::string dstPath = destDirPath + "/" + GetTestFileName(i);
        EXPECT_EQ(DiagOSAPI::RemoveF(dstPath), 0);
        EXPECT_FALSE(IsFileExists(dstPath));
    }

    EXPECT_EQ(DiagOSAPI::RemoveF(destDirPath), 0);
    EXPECT_FALSE(IsDirExists(destDirPath));
}

TEST_F(TestDiagosAPIFixture, TestTopCpuLog)
{
    std::stringstream topCpuLog;
    EXPECT_EQ(DiagOSAPI::TopCpuLog(topCpuLog), 0);
    std::cout << "TopCpuLog: " << topCpuLog.str() << "\n";
}

TEST_F(TestDiagosAPIFixture, TestTopMemLog)
{
    std::stringstream topMemLog;
    EXPECT_EQ(DiagOSAPI::TopMemLog(topMemLog), 0);
    std::cout << "topMemLog: " << topMemLog.str() << "\n";
}

TEST_F(TestDiagosAPIFixture, TestTopDiskLog)
{
    if (std::system("iostat -V > /dev/null 2>&1") != 0)
    {
        GTEST_SKIP() << "Top Disk Log";
    }
    std::stringstream topDiskLog;
    EXPECT_EQ(DiagOSAPI::IOTopDiskLog(topDiskLog), 0);
    std::cout << "topDiskLog: " << topDiskLog.str() << "\n";
}